package cn.seu.together.utils;

import cn.seu.together.annotation.SerializedField;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.lang.reflect.Field;
import java.util.*;
import java.util.List;

/**
 * Created by corvo on 2/15/17.
 *
 * Study from http://lib.csdn.net/article/java/33666
 *
 * 实现ResponseBodyAdvice接口, 通过此接口即可实现对于字段的过滤和加密,
 *
 */
@Order(1)
@ControllerAdvice(basePackages = "cn.seu.together.controllers")
public class MyResponseBodyAdvice implements ResponseBodyAdvice{


    private String[] includes = {};

    private String[] excludes = {};

    private boolean encode = true;

    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        /* 此处自行添加需求 */

        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        includes = new String[]{};
        excludes = new String[]{};
        encode = true;

        if (body == null)
            return null;

        if (returnType.getMethod().isAnnotationPresent(SerializedField.class)) {
            //获取注解配置的包含和去除字段
            SerializedField serializedField = returnType.getMethodAnnotation(SerializedField.class);
            includes = serializedField.includes();
            excludes = serializedField.excludes();
            //是否加密
            encode = serializedField.encode();
        }

        Object retObj = null;
        if (body instanceof List) {
            List list = (List) body;
            retObj = handleList(list);
        } else {
            retObj = handleSingleObject(body);
        }
        return retObj;
    }

    /**
     * 处理返回值是单个entity对象
     * @param o
     * @return
     */
    private Object handleSingleObject(Object o) {
        Map<String, Object> map = new HashMap<String, Object>();
        Field[] fields = o.getClass().getDeclaredFields();
        for (Field field : fields) {
            if (includes.length == 0 && excludes.length == 0) {
                String newVal = getNewVal(o, field);
                map.put(field.getName(), newVal);
            } else if (includes.length > 0) {
                if (Helper.isStringInArray(field.getName(), includes)) {
                    String newVal = getNewVal(o, field);
                    map.put(field.getName(), newVal);
                }
            } else {
                if (excludes.length > 0) {
                    if (!Helper.isStringInArray(field.getName(), excludes)) {
                        String newVal = getNewVal(o, field);
                        map.put(field.getName(), newVal);
                    }
                }
            }
        }

        return map;
    }

    private List handleList(List list) {
        List retList = new ArrayList();
        for (Object o : list) {
            Map map = (Map) handleSingleObject(o);
            retList.add(map);
        }

        return retList;
    }

    /**
     * 此处调用加密算法进行加密操作
     * @param o
     * @param field
     * @return
     */
    private String getNewVal(Object o, Field field) {
        String newVal = "";
        try {
            field.setAccessible(true);
            Object val = field.get(o);
            if (val != null) {
                if (encode) {
                    /** 此处进行加密处理 */
                    newVal = Helper.encode(val.toString());
                } else {
                    newVal = val.toString();
                }
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return newVal;
    }
}
